<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title> 水墨画</title>

  <style>
  @import url(https://fonts.googleapis.com/css?family=Poiret+One);
html {
	overflow: hidden;
	touch-action: none;
	content-zooming: none;
}
body {
	position: absolute;
	margin: 0;
	padding: 0;
	background: #111;
	width: 100%;
	height: 100%;
}
#canvas {
	width: 100%; 
	height: 100%;
	background: #fff;
	position: absolute;
}
#text {
	position:absolute;
	left:0;
	bottom:10px;
	width:100%;
	pointer-events:  none;
}

#text div {
	position:absolute;
	color:#888;
	left:0;
	width:100%;
	text-align:center;
	top:-32px;
	font-family: 'Poiret One', cursive;
	font-size:32px;
}
  </style>
 </head>

<body>

<canvas id="canvas"></canvas>

<div id="text">
	<div id="clic" nowrap>this pen is mouse/touch interactive</div>
</div>

  <script>
  ! function () {

	"use strict";

	// branch constructor

	function Branch (parent, level, x, y) {

		this.parent = parent;
		this.branches = [];
		this.p0 = parent ? parent.p1 : new Point(x, y);
		this.p1 = new Point(x, y);
		this.level = level;
		this.life = 20;
		this.angle = 0;
		this.vx = 0;
		this.vy = 0;

	}

	// grow branch

	Branch.prototype.grow = function () {

		// recursively grow children branches

		for (var i = 0; i < this.branches.length; i++) {

			this.branches[i].grow();

		}

		// grow branch

		if (this.life > 1) {

			this.p1.x += this.vx;
			this.p1.y += this.vy;

			ctx.beginPath();
			ctx.lineCap = "round";

			if (this.level) {

				// draw branch

				ctx.lineWidth = this.level * 6 - 5;
				ctx.strokeStyle = "#000";

				if (this.parent) {

					ctx.moveTo(this.parent.p0.x, this.parent.p0.y);
					ctx.quadraticCurveTo(this.p0.x, this.p0.y, this.p1.x, this.p1.y);

				}

				ctx.stroke();

			} else {

				// draw leaf

				ctx.lineWidth = 10;
				ctx.strokeStyle = "#f40";
				ctx.moveTo(this.p0.x, this.p0.y);
				ctx.lineTo(this.p1.x, this.p1.y);
				ctx.stroke();

			}
		}

		// create sub branches

		if (this.life === 1 && this.level > 0 && this.level < maxLevels) {

			this.branches.push(newBranch(this));
			this.branches.push(newBranch(this));

		}

		// decrement branch life

		this.life--;

	}

	// point 2D constructor

	function Point (x, y) {

		this.x = x;
		this.y = y;

	}

	// new branch factory

	function newBranch (parent) {

		var branch = new Branch (parent, parent.level - 1, parent.p1.x, parent.p1.y);

		branch.angle = (autorun && parent.level === maxLevels) ? Math.random() * 2 * Math.PI : Math.atan2(
			parent.p1.y - parent.p0.y, 
			parent.p1.x - parent.p0.x 
		) + (Math.random() * 1.4 - 0.7);

		branch.vx = Math.cos(branch.angle) * 12;
		branch.vy = Math.sin(branch.angle) * 12;

		branch.life = branch.level === 1 ? 5 : Math.round(Math.random() * (branch.level * 2)) + 2;

		return branch;

	}

	// main animation loop

	function run () {

		// request next frame

		requestAnimationFrame(run);

		// clear screen (with a bit of magic)

		if (++frame % 2) {

			ctx.globalCompositeOperation = "lighter";
			ctx.fillStyle = "rgba(255,255,255,0.01)";
			ctx.fillRect(0, 0, canvas.width, canvas.height);
			ctx.globalCompositeOperation = "source-over";
		}

		// follow the pointer

		current.p1.x = pointer.x;
		current.p1.y = pointer.y;

		// grow tree

		root.grow();

		// create trunk branches

		if ((autorun && Math.random() > 0.8) || pointer.moveDistance > 20) {

			pointer.moveDistance = 0;
			var branch = new Branch (current, current.level, current.p1.x, current.p1.y);
			current.branches.push(branch);

			if (Math.random() > 0.8) current.branches.push(newBranch(current));

			current = branch;
			nBranches++;
			
		}

		// cut the tree

		if (nBranches > maxBranches) {

			root = root.branches[0];
			nBranches--;

		}

	}


	// prepare the canvas

	var canvas = {
		elem: document.getElementById('canvas'),
		width: 0,
		height: 0,
		resize: function () {
			this.width  = this.elem.width  = this.elem.offsetWidth;
			this.height = this.elem.height = this.elem.offsetHeight;
		}
	}

	var ctx = canvas.elem.getContext("2d");
	canvas.elem.onselectstart = function() { return false; }
	canvas.elem.ondragstart = function() { return false; }
	window.addEventListener('resize', canvas.resize.bind(canvas), false);
	canvas.resize();

	// pointer events
	var pointer = {

		x:  canvas.width * 0.5, 
		y:  canvas.height * 0.5,
		px: 0,
		py: 0,
		moveDistance: 0,

		move: function (e) {

			e.preventDefault();
			var pointer = e.targetTouches ? e.targetTouches[0] : e;

			this.x = pointer.clientX;
			this.y = pointer.clientY;

			var dx = this.x - this.px;
			var dy = this.y - this.py;

			this.moveDistance += Math.sqrt(dx * dx + dy * dy);

			// speed limit

			if (this.moveDistance > 40) {

				this.x = this.px + dx * 0.1;
				this.y = this.py + dy * 0.1;
				
			}


			// cancel autorun

			if (autorun) {

				this.x  = pointer.clientX;
				this.y  = pointer.clientY;
				root = new Branch (false, maxLevels, this.x, this.y);
				current = root;
				autorun = false;
				document.getElementById("clic").innerHTML = "";

			}

			this.px = this.x;
			this.py = this.y;

		}
	}

	window.addEventListener("mousemove", pointer.move.bind(pointer), false );
	canvas.elem.addEventListener("touchmove", pointer.move.bind(pointer), false );

	// variables
	
	var maxLevels = 7;
	var nBranches = 0;
	var maxBranches = 200;
	var autorun = true;
	var frame = 0;
	var root = new Branch (false, maxLevels, pointer.x, pointer.y);
	var current = root;

	// start

	run();

}();
  </script>
  
</body>
</html>
